package image;

import java.awt.Color;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;
/**A text field which only allows integers as input.*/
public class IntegerField extends JTextField implements FocusListener, DocumentListener
	{
	private static final long serialVersionUID = 2542178033197173136L;
	
	private PropertyChangeSupport pcs;
	private Integer minimum,maximum;
	private int value;
	private Color defaultColor;
	
	/**
	 * 
	 * @param min Minimum permitted value. May be null for none.
	 * @param max Maximum permitted value. May be null for none.
	 * @param currentValue The initial value.
	 * @param cols The number of "columns" reserved for the text field. 
	 */
	public IntegerField(Integer min, Integer max, int currentValue, int cols)
		{
		super(cols);
		defaultColor = getBackground();
		addFocusListener(new java.awt.event.FocusAdapter() {
        public void focusGained(java.awt.event.FocusEvent evt) {
            SwingUtilities.invokeLater( new Runnable() {
            	@Override public void run() {
	            	setCaretPosition(getText().length());//Select all
	        		moveCaretPosition(0);              
            }});}});

		
		minimum=min;
		maximum=max;
		pcs = new PropertyChangeSupport(this);
		value = currentValue;
		setTextWithNoEvents(String.valueOf(value));
		this.addFocusListener(this);
		getDocument().addDocumentListener(this);
		}
	public void setValue(int newValue,boolean setText, boolean fireEvents)
		{
		if(setText)
			{
			String newText = String.valueOf(newValue);
			setTextWithNoEvents(newText);
			}
		setBackground(defaultColor);
		if(fireEvents)
			pcs.firePropertyChange("VALUE",value,newValue);
		value=newValue;
		}
	public int getValue()
		{
		return value;
		}

	@Override
	public void focusGained(FocusEvent e)
		{
		//setCaretPosition(getText().length());
		//moveCaretPosition(0);
		}

	@Override
	public void focusLost(FocusEvent e)
		{
		Integer newValue = valueOf(getText());
		if (newValue==null)
			{
			setTextWithNoEvents(String.valueOf(value));
			setBackground(defaultColor);
			}
		//value will already be consistent with text
		}
	private void setTextWithNoEvents(String s)
		{
		setDocument(new PlainDocument());
		setText(s);
		getDocument().addDocumentListener(this);
		}
	
	private Integer valueOf(String s)
		{
		try
			{
			return Integer.parseInt(s);
			}
		catch(NumberFormatException e)
			{
			return null;
			}
		}

	public void addValuePropertyChangeListener(PropertyChangeListener obj)
		{
		pcs.addPropertyChangeListener(obj);
		}
	@Override
	public void changedUpdate(DocumentEvent e)
		{
		System.err.println("Wtf is this");
		/*try {documentChanged(e.getDocument().getText(0, e.getDocument().getLength()));}
		catch (BadLocationException e1){}*/
		}
	@Override
	public void insertUpdate(DocumentEvent e)
		{
		try {documentChanged(e.getDocument().getText(0, e.getDocument().getLength()));}
		catch (BadLocationException e1){}
		}
	@Override
	public void removeUpdate(DocumentEvent e)
		{
		try {documentChanged(e.getDocument().getText(0, e.getDocument().getLength()));}
		catch (BadLocationException e1){}
		}
	public void documentChanged(String newString)
		{
		Integer newValue = valueOf(newString);
		if(maximum != null && newValue!=null && newValue>maximum)
				newValue=null;
			if(minimum != null && newValue!=null && newValue<minimum)
				newValue=null;
		if (newValue!=null)
			{
			setValue(newValue,false,true);
			}
		else
			{
			setBackground(Color.RED);
			}
		}
	/**
	 * Set the new minimum value
	 * @param minimum The new minimum value. Null for none.
	 * @param updateValue Whether to change the existing value if it is less than the new minimum
	 * @param fireEvents Whether to fire events if the current value was updated
	 */
	public void setMinimumValue(Integer minimum, boolean updateValue, boolean fireEvents)
		{
		this.minimum = minimum;
		if(minimum != null && getValue()<minimum)
			setValue(minimum, true, fireEvents);
		}
	/**
	 * Set the new maximum value
	 * @param maximum The new maximum value. Null for none.
	 * @param updateValue Whether to change the existing value if it is larger than the new maximum
	 * @param fireEvents Whether to fire events if the current value was updated
	 */
	public void setMaximumValue(Integer maximum, boolean updateValue, boolean fireEvents)
		{
		this.maximum = maximum;
		if(maximum != null && getValue()>maximum)
			setValue(maximum, true, fireEvents);
		}

	}
